using System;
using System.Collections;
using System.Data;
using System.Data.SqlClient;
using System.Web.UI.WebControls;
using PHSRAG.Insight21.Common.Pages;
using PHSRAG.Insight21.Context;
using PHSRAG.Insight21.InsightWorkFlow;
using PHSRAG.Insight21.Policy;
using PHSRAG.Utility;

namespace PHSRAG.Insight21.Humans
{
    /// <summary>
    /// This is the page where users take actions on their Workflow items. This page uses Skelta Workflow's activity control.
    /// This control has two parts in it, list in datagrid form and detail of the item. Detail section has custom document view,
    /// comments tetxt and Accept and Reject buttons. The look and feel of this cotnrol can be changed by changing Activity.xml which
    /// resides in WorkflowElement - Activities - Config folder (actual path Workflow.NET\WorkflowElements\eIRBWFApp\en-US\Activities\Config)
    /// in Skelta installation.
    /// </summary>
    public partial class WorkFlowActivityDetail : BasePage
    {
        #region Constants

        private const string AnnunciatorTitle = "The following error(s) occurred...";
        private const string CachedProtocolIdKey = "cachedProtIdKey_C8CAACFE-9767-4810-AA41-433E0C9A24B8";
        private const string WFActivityDetailIdKey = "wfActivityDetailIdKey_C8CAACFE-9767-4810-AA41-433E0C9A24B8";
        private const string WorkflowCommandName = "Workflow";

        #endregion

        #region Private Variables

        private int accessLevel;
        private ICachePolicy cachePolicy;
        private string moduleType = string.Empty;
        private Hashtable pageCache;
        private ICachePolicy pageCachePolicy;
        private Protocol protocol;
        private int protocolId;
        private string protocolModuleType;
        private ProtocolProcess protocolProcess;
        private int protocolProcessId;
        private int wfExecutionId;
        private string wfActivityNeedAction;
        #endregion

        #region private properties

        /// <summary>
        /// Gets the protocol .If it's not already in the cache, it loads it up based on the protocolId passed to 
        /// the page, and caches the object.
        /// </summary>				
        private Protocol Protocol
        {
            get
            {
                string cacheKey = Protocol.ProtocolKey;
                protocol = cachePolicy.GetCachedObject(cacheKey) as Protocol;

                if ((protocol == null) || (protocolId != protocol.Id))
                {
                    protocol = new Protocol(cachePolicy);
                    protocol.Load(DataAccess.GetConnectionString(), protocolId);
                    cachePolicy.Cache(cacheKey, protocol);
                }
                return protocol;
            }
        }

        /// <summary>
        /// Gets the protocol process . If it's not already
        /// in the cache, it loads it up based on the protocolProcessId passed to the page, and caches the 
        /// object
        /// </summary>
        private ProtocolProcess ProtocolProcess
        {
            get
            {
                protocolProcess = cachePolicy.GetCachedObject(ProtocolProcess.ProtocolProcessKey)
                    as ProtocolProcess;

                if ((protocolProcess == null) || (protocolProcessId != protocolProcess.Id))
                {
                    if (protocolProcessId != 0)
                    {
                        protocolProcess = ProtocolProcess.GetProtocolProcess(
                            DataAccess.GetConnectionString(), protocolProcessId, cachePolicy, null);
                        cachePolicy.Cache(ProtocolProcess.ProtocolProcessKey, protocolProcess);
                    }
                    else
                    {
                        protocolProcess = null;
                    }
                }
                return protocolProcess;
            }
        }

        /// <summary>
        /// ReadOnly property to get module type that is to be passed in as a parameter to the load method
        /// </summary>
        private string ModuleType
        {
            get
            {
                if (moduleType == string.Empty)
                {
                    moduleType = (header.ModuleName.ToLower() == "animals") ? "A" : "H";
                }

                return moduleType;
            }
        }

        #endregion

        #region Events

        /// <summary>
        /// Sets the breadcrumb. Sets logged in user id to Skelta WorkflowActivity control's UserId property.
        /// Also, it sets filter on the activity control to make sure only selected Protocol Process appears in the control.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        protected void OnPageLoad(object sender, EventArgs e)
        {
            pageCache = pageCachePolicy.GetCachedObject(WFActivityDetailIdKey) as Hashtable;
            UserContext userContext = (UserContext) cachePolicy.GetCachedObject(UserContext.CacheKey);

            if (userContext == null)
            {
                Server.Transfer(Settings.GetKeyValue("Header.Logout", "") + "?message=" + "You are not logged in, please log into the system.", true);
            }

            //The following "if" block is to redirect this page back to the activity tracking page.
            if (Request.QueryString.HasKeys())
            {
                if ((Request.QueryString.GetValues("ActivityId") == null) && (Request.QueryString.GetValues("ExecutionId") == null))
                {
                    OnHumansSubModNavigate();
                    Response.Redirect(Settings.GetKeyValue("SubNavigation.Humans.WorkFlowActivityListURL", "WorkflowActivity.aspx"));
                }
                if (Request.QueryString.GetValues("ExecutionId") != null)
                {
                    wfExecutionId = Convert.ToInt32(Request.QueryString["ExecutionId"]);
                    protocolProcessId = Convert.ToInt32(Request.QueryString["PPId"]);

                    SqlParameter[] args = DataAccess.BuildSqlParameterArray("@executionId", SqlDbType.Int, wfExecutionId,
                        "@domainUserId", SqlDbType.Int, userContext.DomainUserId);

                    SqlDataReader reader = DataAccess.ExecuteReader(DataAccess.GetConnectionString(), "GetWorkflowProtocolDetails", args);

                    /*email helpdesk with the delimited usernames*/
                    if (reader.Read())
                    {
                        protocolId = Convert.ToInt32(reader["ProtocolId"].ToString());
                        accessLevel = Convert.ToInt32(reader["AccessLevel"].ToString());
                        protocolModuleType = reader["ModuleType"].ToString();

                        if (accessLevel == 0)
                        {
                            annunciator.Message = "You do not have access rights to this protocol, by clicking on any details for this protocol the system will log you out.";
                        }

                        pageCache = new Hashtable();

                        pageCache[CachedProtocolIdKey] = protocolId;
                        pageCache[Keys.ProtocolProcessIdKey] = protocolProcessId;
                        pageCache[Keys.ProtocolAccessKey] = accessLevel;
                        pageCache[Keys.WFExecutionIdKey] = wfExecutionId;
                        pageCachePolicy.Cache(WFActivityDetailIdKey, pageCache);

                        ProtocolProcess protocolProcess = ProtocolProcess.GetProtocolProcess(
                            DataAccess.GetConnectionString(), protocolProcessId, cachePolicy, null);
                        cachePolicy.Cache(Keys.ProtocolProcessKey, protocolProcess);
                    }
                }
            }

            viewFullApplication.OnClientClick = "javascript:window.open('ViewFullProtocolPage.aspx', 'Application', 'width=800, height=600, status=yes, toolbar=no, resizable=yes');return false;";
            viewApplication.OnClientClick = "javascript:window.open('ViewProtocolPage.aspx', 'Application', 'width=800, height=600, status=yes, toolbar=no, resizable=yes');;return false;";

            breadCrumb.Add(
                " Workflow",
                Settings.GetKeyValue("SubModuleNavigation.Humans.WorkflowURL", ""),
                Settings.GetKeyValue("BreadCrumb.DetailPageLevel", 2));

            if ((protocolModuleType != String.Empty) && (protocolModuleType != null))
            {
                humansSubModuleNavigation.Visible = (protocolModuleType == "H") ? true : false;
            }
            else
            {
                humansSubModuleNavigation.Visible = (ModuleType == "H") ? true : false;
            }

            animalsSubModuleNavigation.Visible = !humansSubModuleNavigation.Visible;

            wfActivity.UserIDInteger = userContext.DomainUserId;
            wfActivity.ApplicationName = Settings.GetKeyValue("InsightApplicationName", string.Empty);

            if (!IsPostBack)
            {
                if (pageCache == null)
                {
                    pageCache = new Hashtable();
                }
                // get id coming from the originating page and clean the cache of all incoming data
                Hashtable incomingPageHash = cachePolicy.GetCachedObject(Keys.IncomingDataKey) as Hashtable;
                if (incomingPageHash != null)
                {
                    protocolId = Convert.ToInt32(incomingPageHash[Keys.ProtocolIdKey]);
                    protocolProcessId = Convert.ToInt32(incomingPageHash[Keys.ProtocolProcessIdKey]);
                    wfExecutionId = Convert.ToInt32(incomingPageHash[Keys.WFExecutionIdKey]);
                    if (wfExecutionId == 0)
                    {
                        HumansWorkFlow humansWorkFlow = new HumansWorkFlow(cachePolicy);
                        ProtocolProcess process = ProtocolProcess;
                        if (process != null)
                        {
                            if (process.Resubmission)
                            {
                                wfExecutionId = humansWorkFlow.GetWorkflowItemIdByType(protocolProcessId, "RESUB");
                            }
                            else
                            {
                                wfExecutionId = humansWorkFlow.GetWorkflowItemId(protocolProcessId);
                            }
                        }
                    }
                    accessLevel = Convert.ToInt32(incomingPageHash[Keys.ProtocolAccessKey]);
                    wfActivityNeedAction =  Convert.ToString(incomingPageHash[Keys.WFNeededActionKey]);
                    cachePolicy.UnCache(Keys.IncomingDataKey);

                    // get any data that's been cached from previous hits to the page;
                    // if there's data in the cache for this page, and if the protocolId is different 
                    // than the one for which data is cached, flush the cache
                    object cachedProtId = pageCache[CachedProtocolIdKey];
                    if (cachedProtId != null)
                    {
                        int cachedId = Convert.ToInt32(cachedProtId);
                        if (cachedId != protocolId)
                        {
                            UnCachePageData();
                            pageCache[CachedProtocolIdKey] = cachedId;
                        }
                    }
                    else
                    {
                        UnCachePageData();
                    }

                    pageCache[CachedProtocolIdKey] = protocolId;
                    pageCache[Keys.ProtocolProcessIdKey] = protocolProcessId;
                    pageCache[Keys.ProtocolAccessKey] = accessLevel;
                    pageCache[Keys.WFExecutionIdKey] = wfExecutionId;
                    pageCache[Keys.WFNeededActionKey] = wfActivityNeedAction;
                    pageCachePolicy.Cache(WFActivityDetailIdKey, pageCache);
                }
                else // incomingPageHash is null
                {
                    protocolId = (int) pageCache[CachedProtocolIdKey];
                    protocolProcessId = (int) pageCache[Keys.ProtocolProcessIdKey];
                    wfExecutionId = (int) pageCache[Keys.WFExecutionIdKey];
                    accessLevel = (int) pageCache[Keys.ProtocolAccessKey];
                    wfActivityNeedAction = (string)pageCache[Keys.WFNeededActionKey];
                }

                if ((header.ModuleName == null) || (header.ModuleName == string.Empty))
                {
                    header.ModuleName = (protocolModuleType == "H") ? "Humans" : "Animals";
                }

                if (header.ModuleName.ToLower() == "animals")
                {
                    animalsSubModuleNavigation.SelectedLink = WorkflowCommandName;
                }
                else
                {
                    humansSubModuleNavigation.SelectedLink = WorkflowCommandName;
                }
            }
            else
            {
                protocolId = Int32.Parse(pageCache[CachedProtocolIdKey].ToString());
                protocolProcessId = Int32.Parse(pageCache[Keys.ProtocolProcessIdKey].ToString());
                wfExecutionId = Int32.Parse(pageCache[Keys.WFExecutionIdKey].ToString());
                accessLevel = Int32.Parse(pageCache[Keys.ProtocolAccessKey].ToString());
                wfActivityNeedAction = (string)pageCache[Keys.WFNeededActionKey];
            }
            //InsightWorkFlow.HumansWorkFlow humansWorkFlow = new InsightWorkFlow.HumansWorkFlow(cachePolicy);  
            //int executionId = humansWorkFlow.GetWorkflowItemId(Int32.Parse(pageCache[Keys.ProtocolProcessIdKey].ToString()));
            //if (executionId > 0)	
            SetupPageForModuleType();
            wfActivity.BaseActivityFilter = " and SWA.ExecutionId = " + wfExecutionId;
            if (wfActivityNeedAction != null)
                wfActivity.BaseActivityFilter += " and SWA.ActionRequired = '" + wfActivityNeedAction + "' ";
            wfActivityDetailHeader.ProtocolID = protocolId;
        }

        /// <summary>
        /// Make necessary changes to page for use by Animals or Humans
        /// </summary>
        protected void SetupPageForModuleType()
        {
            if (header.ModuleName.ToLower() == "animals")
            {
                animalsSubModuleNavigation.Visible = true;
                humansSubModuleNavigation.Visible = !animalsSubModuleNavigation.Visible;
                animalsSubModuleNavigation.ProtocolProcess = ProtocolProcess;
                animalsSubModuleNavigation.Protocol = Protocol;
            }
            else
            {
                //Set the Human sub mod Navigation links
                humansSubModuleNavigation.Visible = true;
                animalsSubModuleNavigation.Visible = !humansSubModuleNavigation.Visible;
                humansSubModuleNavigation.ProtocolProcess = ProtocolProcess;
                humansSubModuleNavigation.Protocol = Protocol;
            }
        }

        /// <summary>
        /// Resets the subnavigation selected link before the breadCrumb performs a redirect.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        private void OnBreadCrumbNavigate(object sender, CommandEventArgs e)
        {
            try
            {
                RefreshObjects();
                humansSubModuleNavigation.Reset();
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Resets the subnavigation selected link before the header or the breadCrumb performs a redirect.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        private void OnNavigate(object sender, CommandEventArgs e)
        {
            try
            {
                RefreshObjects();
                humansSubModuleNavigation.Reset();
                animalsSubModuleNavigation.Reset();
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Constructs and caches a hashtable of data for use by the page to which nagivation leads
        /// </summary>
        private void OnHumansSubModNavigate(object sender, EventArgs e)
        {
            OnHumansSubModNavigate();
        }

        /// <summary>
        /// Constructs and caches a hashtable of data for use by the page to which nagivation leads
        /// </summary>
        private void OnHumansSubModNavigate()
        {
            try
            {
                RefreshObjects();
                Hashtable outgoingData = new Hashtable();
                outgoingData.Add(Keys.ProtocolIdKey, protocolId);
                outgoingData.Add(Keys.ProtocolProcessIdKey, protocolProcessId);
                outgoingData.Add(Keys.ProtocolAccessKey, accessLevel);
                outgoingData.Add(Keys.WFExecutionIdKey, wfExecutionId);
                pageCachePolicy.Cache(Keys.IncomingDataKey, outgoingData);

                if (accessLevel == 0)
                {
                    Server.Transfer(Settings.GetKeyValue("Header.Logout", "") + "?message=" + "You did not have access to this protocol please log into the system again.", true);
                }
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Do cleanup on unload to manage memory bloat.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        protected void OnUnload(object sender, EventArgs e)
        {
            wfActivity.Dispose();
        }

        #endregion

        #region Web Form Designer generated code

        protected override void OnInit(EventArgs e)
        {
            //
            // CODEGEN: This call is required by the ASP.NET Web Form Designer.
            //
            InitializeComponent();
            base.OnInit(e);
            cachePolicy = (Policy.ICachePolicy) Session[Policy.Names.CachePolicyKey];
            pageCachePolicy = (Policy.ICachePolicy) Session[Policy.Names.PageCachePolicyKey];
        }

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.header.Navigate += new System.Web.UI.WebControls.CommandEventHandler(this.OnNavigate);
            this.humansSubModuleNavigation.Navigate += new PHSRAG.Insight21.InsightWebControls.HumansSubModuleNavigation.NavigateEventHandler(this.OnHumansSubModNavigate);
            this.animalsSubModuleNavigation.Navigate += new CommandEventHandler(this.OnHumansSubModNavigate);
            this.breadCrumb.Navigate += new System.Web.UI.WebControls.CommandEventHandler(this.OnBreadCrumbNavigate);
            this.Unload += new System.EventHandler(this.OnUnload);
            this.Load += new System.EventHandler(this.OnPageLoad);
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Displays an error message on the screen to the user with the exception, and all
        /// inner exception messages.
        /// </summary>
        /// <param name="ex">The exception to report on</param>
        private void DisplayExceptionReport(Exception ex)
        {
            annunciator.Title = AnnunciatorTitle;
            annunciator.Message = ExceptionReport.GetExceptionInfo(ex, false);
        }

        /// <summary>
        /// Resets the hash table that stores page data, and also the cachedProtocolId, 
        /// which indicate which protocol the cached page data is based on
        /// </summary>
        private void UnCachePageData()
        {
            pageCachePolicy.UnCache(CachedProtocolIdKey);

            pageCache = new Hashtable();
            pageCachePolicy.Cache(WFActivityDetailIdKey, pageCache);
        }

        /// <summary>
        /// Uncahce, load and cache (Refresh) Protocol and Protocol Process objects.
        /// </summary>
        private void RefreshObjects()
        {
            cachePolicy.UnCache(Protocol.ProtocolKey);
            cachePolicy.UnCache(ProtocolProcess.ProtocolProcessKey);

            protocol = Protocol;
            protocolProcess = ProtocolProcess;
        }

        #endregion
    }
}